# @Version        : 1.0
# @Update Time    : 2024/9/17 10:52
# @File           : menu_service.py
# @IDE            : PyCharm
# @Desc           : 菜单服务
from typing import Optional

from advanced_alchemy import service
from asyncer import asyncify
from sqlalchemy import and_, false
from src import models, schemas
from src.models import SysUser
from src.schemas.user_info_schema import UserInfo
from src.crud.menu_repository import MenuRepo


class MenuService(service.SQLAlchemyAsyncRepositoryService[models.SysMenu, MenuRepo]):
    repository_type = MenuRepo
    count_with_window_function = True

    # 获取树状菜单列表
    async def route_tree(self):
        res = await super().list(
            and_(
                models.SysMenu.constant == false(),
                models.SysMenu.status == "1",
                models.SysMenu.menu_type != "3",
            )
        )
        res_schema = [schemas.MenuOut.model_validate(menu) for menu in res]
        tree_list = await asyncify(self.build_route_tree)(res_schema, None, True)
        return tree_list

    def build_route_tree(
        self, menus: list[schemas.MenuOut], parent_id: Optional[int] = None, simple: bool = False
    ) -> list[dict]:
        """
        递归生成路由树
        :param menus:
        :param parent_id:
        :param simple: 是否简化返回数据
        :return:
        """
        tree = []
        for menu in menus:
            if (parent_id is None and (menu.parent_id in (None, 0))) or (parent_id is not None and menu.parent_id == parent_id):
                children = self.build_route_tree(menus, menu.id, simple)
                if simple:
                    if not menu.href:
                        menu_dict = {
                            "name": menu.route_name,
                            "path": menu.route_path,
                            "component": menu.component,
                            "meta": {
                                "title": menu.menu_name,
                                "i18nKey": menu.i18n_key,
                                "order": menu.order,
                                # "roles": role_codes,  # todo roles
                                "keepAlive": menu.keep_alive,
                                "icon": menu.icon,
                                "iconType": menu.icon_type,
                                "href": menu.href,
                                "activeMenu": menu.active_menu,
                                "multiTab": menu.multiple_tab,
                                "fixedIndexInTab": menu.fixed_index_in_tab,
                            },
                        }
                    else:
                        menu_dict = {
                            "name": menu.route_name,
                            "path": menu.route_path,
                            "component": menu.component,
                            "props": {
                                "url": menu.href,
                            },
                            "meta": {
                                "title": menu.menu_name,
                                "i18nKey": menu.i18n_key,
                                "order": menu.order,
                                "icon": menu.icon,
                            },
                        }
                    if menu.redirect:
                        menu_dict["redirect"] = menu.redirect
                    if menu.component and menu.component.find("$") != -1:
                        menu_dict["meta"]["layout"] = menu.component.split(
                            "$", maxsplit=1
                        )[0]
                    if menu.hide_in_menu and not menu.constant:
                        menu_dict["meta"]["hideInMenu"] = menu.hide_in_menu
                else:
                    menu_dict = menu.model_dump()
                if children:
                    menu_dict["children"] = children
                tree.append(menu_dict)
        return tree

    def to_tree_data(self, res: list, parent_id: int = 0) -> list:
        lst = []
        for item in res:
            new_dict = {
                "name": item.menu_name,
                "path": item.route_path,
                "component": item.component,
                "meta": {
                    "title": item.menu_name,
                    "i18nKey": item.i18n_key,
                    "icon": item.icon,
                    "order": item.order,
                    "keepAlive": item.keep_alive,
                },
            }
            if item.parent_id == parent_id:
                d = self.to_tree_data(res, item.id)
                if d:
                    new_dict["children"] = d
                lst.append(new_dict)
        return lst

    def to_tree_data_2(self, res: list, parent_id: int = 0) -> list:
        lst = []
        for item in res:
            if item.get("parent_id") == parent_id:
                children = self.to_tree_data_2(res, item.get("id"))
                if children:
                    item["children"] = children
                lst.append(item)
        return lst

    async def get_user_menu(self, user: SysUser) -> list[dict]:
        if user.is_super_admin():
            res = await self.route_tree()
        else:
            data: list[schemas.MenuOut] = []
            for role in user.roles:
                for menu in role.menus:
                    if (
                        menu.status == "1"
                        and not menu.constant
                        and menu.menu_type != "3"
                    ):
                        data.append(schemas.MenuOut.model_validate(menu))
            res = []
            if data:
                res = await asyncify(self.build_route_tree)(data, 0, True)
        return res
